/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.collections.sets;

import com.softwarecraftsmen.functors.Boolean;
import static com.softwarecraftsmen.functors.Boolean.False;
import static com.softwarecraftsmen.functors.Boolean.True;
import static com.softwarecraftsmen.functors.Boolean.fromLegacy;
import com.softwarecraftsmen.collections.Key;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.TreeSet;

public class LinkedHashMutableSet<V extends Key> implements Set<V>, MutableSet<V>
{
	private static int Zero = 0;
	private int size;
	private final LinkedHashSet<LegacyCollectionSupport<V>> internalRepresentation;
	private final java.util.List<V> reverseIndex;

	public LinkedHashMutableSet()
	{
		this(new java.util.LinkedHashSet<LegacyCollectionSupport<V>>(), new ArrayList<V>());
	}

	private LinkedHashMutableSet(final @NotNull LinkedHashSet<LegacyCollectionSupport<V>> internalRepresentation, final @NotNull java.util.List<V> reverseIndex)
	{
		this.internalRepresentation = internalRepresentation;
		this.reverseIndex = reverseIndex;
	}

	@SuppressWarnings({"unchecked"})
	@NotNull
	public Set<V> defensiveCopy()
	{
		return new LinkedHashMutableSet<V>((LinkedHashSet<LegacyCollectionSupport<V>>)internalRepresentation.clone(), new ArrayList<V>(reverseIndex));
	}

	@NotNull
	public HashSet<V> toLegacyHashSet()
	{
		return new HashSet<V>(reverseIndex);
	}

	@NotNull
	public LinkedHashSet<V> toLegacyLinkedHashSet()
	{
		return new LinkedHashSet<V>(reverseIndex);
	}

	@NotNull
	public TreeSet<V> toLegacyTreeSet()
	{
		return new TreeSet<V>(reverseIndex);
	}

	@NotNull
	public TreeSet<V> toLegacyTreeSet(final @NotNull Comparator<? super V> comparator)
	{
		final TreeSet<V> treeSet = new TreeSet<V>(comparator);
		treeSet.addAll(reverseIndex);
		return treeSet;
	}

	@NotNull
	public Boolean isEmpty()
	{
		return fromLegacy(size == Zero);
	}

	@NotNull
	public Boolean hasElements()
	{
		return fromLegacy(size != Zero);
	}

	public int size()
	{
		return size;
	}

	@NotNull
	public Boolean contains(final @NotNull Integer key)
	{
		return fromLegacy((-1 < key)).and(fromLegacy((key < size)));
	}

	@NotNull
	public com.softwarecraftsmen.functors.Boolean doesNotContain(final @NotNull Integer key)
	{
		return contains(key).not();
	}

	@NotNull
	public Boolean isMutable()
	{
		return True;
	}

	public void add(final @NotNull V value)
	{
		internalRepresentation.add(legacyCollectionSupport(value));
		reverseIndex.add(value);
		size++;
	}

	@NotNull
	public Boolean isOrdered()
	{
		return True;
	}

	@NotNull
	public Boolean isSorted()
	{
		return False;
	}

	private static <K extends Key> LegacyCollectionSupport<K> legacyCollectionSupport(final K key)
	{
		return new LegacyCollectionSupport<K>(key);
	}

	@NotNull
	public V valueAt(final Integer key)
	{
		return reverseIndex.get(key);
	}

	@NotNull
	public ArrayList<V> toLegacyArrayList()
	{
		return new ArrayList<V>(reverseIndex);
	}

	@NotNull
	public LinkedList<V> toLegacyLinkedList()
	{
		return new LinkedList<V>(reverseIndex);
	}

	@SuppressWarnings({"unchecked"})
	@NotNull
	public V[] toLegacyArray()
	{
		return (V[]) toLegacyArrayList().toArray();
	}

	private static class LegacyCollectionSupport<K extends Key>
	{
		private final K key;

		public LegacyCollectionSupport(final @NotNull K key)
		{
			this.key = key;
		}

		@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
		public boolean equals(final @NotNull Object o)
		{
			return key.isEqualTo(((LegacyCollectionSupport) o).key).toLegacyBoolean();
		}

		public int hashCode()
		{
			return key.computeHashCode();
		}
	}
}
